﻿/**************************************************************************
  exif.h  -- A simple ISO C++ library to parse basic EXIF
             information from a JPEG file.

  Based on the description of the EXIF file format at:
  -- http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
  -- http://www.media.mit.edu/pia/Research/deepview/exif.html
  -- http://www.exif.org/Exif2-2.PDF

  Copyright (c) 2010-2016 Mayank Lahiri
  mlahiri@gmail.com
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  -- Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
  -- Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
   NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __EXIF_H
#define __EXIF_H

#include <string>

//
// 负责存储和解析JPEG blob中的EXIF信息
//
class EXIFInfo {
 public:
  // 整个JPEG图像缓冲区的解析函数
  //
  // data：指向JPEG图像的指针
  // length：JPEG图像的长度
  // 解析成功返回：PARSE_EXIF_SUCCESS
  // 解析失败返回：PARSE_EXIF_ERROR_XXX (例如PARSE_EXIF_ERROR_NO_EXIF)
  int parseFrom(const unsigned char *data, unsigned length);
  int parseFrom(const std::string &data);

  // 正在分析EXIF段的函数。parseFrom（）内部使用但是可以在只有EXIF部分的特殊情况下调用（即，以字节“Exif\0\0”开头的blob）。
  int parseFromEXIFSegment(const unsigned char *buf, unsigned len);

  // 将所有数据成员设置为默认值
  void clear();

  // parseFrom() 执行成功后填写的数据字段
  char ByteAlign;                   // 0=摩托罗拉字节对齐，1=英特尔
  std::string ImageDescription;     // 图像描述
  std::string Make;                 // 相机制造商名称
  std::string Model;                // 相机型号
  unsigned short Orientation;       // 图像方向，数据起始对应
                                    // 0:EXIF数据中未指定
                                    // 1：图像左上角
                                    // 3：图像的右下角
                                    // 6：图像的右上角
                                    // 8：图像左下角
                                    // 9：未定义
  unsigned short BitsPerSample;     // 每个组件的位数
  std::string Software;             // 使用的软件
  std::string DateTime;             // 文件更改日期和时间
  std::string DateTimeOriginal;     // 原始文件日期和时间（可能不存在）
  std::string DateTimeDigitized;    // 数字化日期和时间（可能不存在）
  std::string SubSecTimeOriginal;   // 拍摄原始照片的子秒（日期的秒）
  std::string Copyright;            // 文件版权信息
  double ExposureTime;              // 曝光时间（秒）
  double FNumber;                   // 光圈
  unsigned short ExposureProgram;   // 曝光模式
                                    // 0:未定义
                                    // 1: 手动
                                    // 2：正常程序
                                    // 3: 光圈优先
                                    // 4: 快门优先
                                    // 5: 创意方案
                                    // 6: 运动模式
                                    // 7: 纵向模式
                                    // 8: 横向模式
  unsigned short ISOSpeedRatings;   // ISO
  double ShutterSpeedValue;         // 快门速度（曝光时间的倒数）
  double ExposureBiasValue;         // EV中的曝光偏差值
  double SubjectDistance;           // 到焦点的距离（米）
  double FocalLength;               // 透镜焦距（毫米）
  unsigned short FocalLengthIn35mm; // 35mm胶片的焦距
  char Flash;                       // 0=没有闪光灯，1=使用了闪光灯
  unsigned short FlashReturnedLight;// 闪光灯返回灯状态
                                    // 0：无选通返回检测功能
                                    // 1: 保留
                                    // 2: 未检测到频闪返回光
                                    // 3: 检测到频闪返回光
  unsigned short FlashMode;         // 闪光灯模式
                                    // 0: 未知
                                    // 1: 强制闪光 点火
                                    // 2: 强制闪光 抑制
                                    // 3: 自动模式
  unsigned short MeteringMode;      // 测光模式
                                    // 1: 平均
                                    // 2: 中心加权平均
                                    // 3: 现场
                                    // 4: 多点
                                    // 5: 多段
  unsigned ImageWidth;              // EXIF数据中报告的图像宽度
  unsigned ImageHeight;             // EXIF数据中报告的图像高度
  struct Geolocation_t {            // GPS信息嵌入文件
    double Latitude;                  // 图像纬度以十进制表示
    double Longitude;                 // 以十进制表示的图像经度
    double Altitude;                  // 海拔高度（米），相对于海平面
    char AltitudeRef;                 // 0=海平面以上，-1=海平面以下
    double DOP;                       // GPS精度（DOP）
    struct Coord_t {
      double degrees;
      double minutes;
      double seconds;
      char direction;
    } LatComponents, LonComponents;   // 纬度，经度，单位为度/分/秒
  } GeoLocation;
  struct LensInfo_t {               // 镜头信息
    double FStopMin;                // 最小光圈（f-stop）
    double FStopMax;                // 最大光圈（f-stop）
    double FocalLengthMin;          // 最小焦距（mm）
    double FocalLengthMax;          // 最大焦距（mm）
    double FocalPlaneXResolution;   // 焦平面X分辨率
    double FocalPlaneYResolution;   // 焦平面Y分辨率
    unsigned short FocalPlaneResolutionUnit; //焦平面分辨率单元
                                            //1：没有绝对计量单位。
                                            //2：英寸。
                                            //3：厘米。
                                            //4:毫米。
                                            //5：千分尺。
    std::string Make;               // 镜头制造商
    std::string Model;              // 镜头型号
  } LensInfo;


  EXIFInfo() {
    clear();
  }
};

// 解析成功
#define PARSE_EXIF_SUCCESS                    0
// 在缓冲区中找不到JPEG标记，可能是无效的JPEG文件
#define PARSE_EXIF_ERROR_NO_JPEG              1982
// 在JPEG文件中找不到EXIF标头。
#define PARSE_EXIF_ERROR_NO_EXIF              1983
// EXIF文件中指定的字节对齐方式未知（不是摩托罗拉或英特尔）。
#define PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN    1984
// 找到了EXIF标头，但数据已损坏。
#define PARSE_EXIF_ERROR_CORRUPT              1985

#endif
